# #! -*- coding:utf-8 -*-
#!/usr/bin/python

import codecs,sys,time
import json
import urllib
import urllib2
import time
import datetime
import random
import hashlib
import uuid
import threading
from urllib import quote
import pycurl
from cStringIO import StringIO
import xml.etree.ElementTree as ET
import pymongo
from pymongo import MongoClient

reload(sys)
sys.setdefaultencoding('utf-8')

conn = MongoClient("6dutcm.com",27017)
db = conn.health
db.authenticate("hou","hou@123")

MCH_ID = "1288388201"
APPID = "wx04b131310109a07c"
SECRETKEY = "d41dd4c033f4531b25ab3409390fb6e8"
APIKEY = "d41dd4c033f4531b25ab3409390fb6e8"
SSLCERT_PATH = "/root/ldzy/apiclient_cert.pem"
SSLKEY_PATH = "/root/ldzy/apiclient_key.pem"


class CurlClient(object):
    """使用Curl发送请求"""
    def __init__(self):
        self.curl = pycurl.Curl()
        self.curl.setopt(pycurl.SSL_VERIFYHOST, False)
        self.curl.setopt(pycurl.SSL_VERIFYPEER, False)
        #设置不输出header
        self.curl.setopt(pycurl.HEADER, False)

    def get(self, url, second=30):
        return self.postXmlSSL(None, url, second=second, cert=False, post=False)

    def postXml(self, xml, url, second=30):
        """不使用证书"""
        return self.postXmlSSL(xml, url, second=second, cert=False, post=True)


    def postXmlSSL(self, xml, url, second=30, cert=True, post=True):
        """使用证书"""
        self.curl.setopt(pycurl.URL, url)
        self.curl.setopt(pycurl.TIMEOUT, second)
        #设置证书
        #使用证书：cert 与 key 分别属于两个.pem文件
        #默认格式为PEM，可以注释
        if cert:
            self.curl.setopt(pycurl.SSLKEYTYPE, "PEM")
            self.curl.setopt(pycurl.SSLKEY, SSLKEY_PATH)
            self.curl.setopt(pycurl.SSLCERTTYPE, "PEM")
            self.curl.setopt(pycurl.SSLCERT, SSLCERT_PATH)
        #post提交方式
        if post:
            self.curl.setopt(pycurl.POST, True)
            self.curl.setopt(pycurl.POSTFIELDS, xml)
        buff = StringIO()
        self.curl.setopt(pycurl.WRITEFUNCTION, buff.write)

        self.curl.perform()
        return buff.getvalue()

    def formatBizQueryParaMap(self, paraMap, urlencode):
        """格式化参数，签名过程需要使用"""
        slist = sorted(paraMap)
        buff = []
        for k in slist:
            v = quote(paraMap[k]) if urlencode else paraMap[k]
            buff.append("{0}={1}".format(k, v))

        return "&".join(buff)

    def getSign(self, obj):
        """生成签名"""
        # 签名步骤一：按字典序排序参数,formatBizQueryParaMap已做
        String = self.formatBizQueryParaMap(obj, False)
        # 签名步骤二：在string后加入KEY
        String = "{0}&key={1}".format(String, APIKEY)
        # 签名步骤三：MD5加密
        String = hashlib.md5(String).hexdigest()
        # 签名步骤四：所有字符转为大写
        result_ = String.upper()
        return result_

    def arrayToXml(self, arr):
        """array转xml"""
        xml = ["<xml>"]
        for k, v in arr.iteritems():
            if v.isdigit():
                xml.append("<{0}>{1}</{0}>".format(k, v))
            else:
                xml.append("<{0}><![CDATA[{1}]]></{0}>".format(k, v))
        xml.append("</xml>")
        return "".join(xml)

    def xmlToArray(self, xml):
        """将xml转为array"""
        array_data = {}
        root = ET.fromstring(xml)
        for child in root:
            value = child.text
            array_data[child.tag] = value
        return array_data

    def pay_person(self,openid, money):
        url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'
        params = {}
        params["mch_appid"] = APPID
        nonstr=str(uuid.uuid1()).replace("-", "")
        params["check_name"] = "NO_CHECK"
        params["mchid"] =MCH_ID
        params["nonce_str"] =  nonstr #self.createNoncestr()
        params["partner_trade_no"] =nonstr
        params["amount"] = str(round(money,2)*100)
        params["spbill_create_ip"] = "127.0.0.1"
        params["openid"] = openid
        params["desc"] = "医生预约结算"
        params["sign"] = self.getSign(params)
        self.parameters = json.dumps(params)
        xml = self.arrayToXml(params)
        ret = self.postXmlSSL(xml, url)
        return ret

#对医生计算是否要结算，昨天之前的预约单都要结算。结算成功后计算结算记录，并重新计算用户money
def check_to_pay_money(userId):
    #print "handling ",userId
    orders=[]
    now = datetime.datetime.now()
    today = datetime.datetime.strptime(str(now.year) + "-" + str(now.month) + "-" + str(now.day) + " 00:00:00",
                                       "%Y-%m-%d %H:%M:%S")
    yesterday = today #- datetime.timedelta(days=1)
    contents = db.order.find({'doctorId': userId, "isPayed": True, "given":False,"orderDate": { "$lt": str(yesterday)}}).sort("orderDate",pymongo.ASCENDING)
    total=0.0
    for record in contents:
        if (record["given"]):
            continue
        if (record["pbTimeid"] is None or len(record["pbTimeid"])<1):
            continue
        if (total+record["price"]> 1000):
            break
        else:
            total=total+record["price"]
            orders.append(record["uuid"])
    if total>1.1:
        orimoney=total
        paymoney = round(total*0.95,2)
        #str(uuid.uuid1()).replace("-", "")
        recId=str(uuid.uuid1()).replace("-", "")
        dtr=now.strftime("%Y-%m-%d %H:%M:%S")
        db.ldzycashed.insert({"uuid":recId,"userId":userId,"orders":orders,"name":"",
                              "createtime":dtr,"success":False,"orimoney":orimoney,"money":paymoney})
        if (pay_person(userId,paymoney)):
            print "successfully pay to doctor:",userId," money:",paymoney
            db.ldzycashed.update({'uuid':recId}, {'$set': {'success': True}})
            compute_usermoney(userId)
            for orderId in orders:
                db.order.update({'uuid': orderId}, {'$set': {'given': True}})

def test():
    contents = db.ldzycashed.find({"uuid":"b2d4ba1011b44402bb9e2366eca1d3fe"})
    for line in contents:
        print line
        break

#计算用户的已计算总数
def compute_usermoney(userId):
    money = 0.0
    contents = db.ldzycashed.find( {'userId': userId, "success": True })
    for record in contents:
        money = money+record["orimoney"]
    db.user.update({'userId':userId}, {'$set': {'cashed': round(money,2)}})



#结算给医生用户预约费
def pay_person(userId,money):
    openid=get_openid(userId)
    client =CurlClient()
    ret=client.pay_person(openid,money)
    print ret
    s =client.xmlToArray(ret) #json.loads(ret)
    print s.keys()
    if (s["return_code"].lower() == "success" and s["result_code"].lower()=="success"):
        return True
    else:
        return False

def get_token():
    url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"
    url=url.replace("APPID",APPID).replace("APPSECRET",SECRETKEY)
    #jdata = json.dumps(values)  # 对数据进行JSON格式化编码
    req = urllib2.Request(url) #, jdata)  # 生成页面请求的完整数据
    response = urllib2.urlopen(req)  # 发送页面请求
    retstr= response.read()
    return json.loads(retstr)["access_token"]

#获取用户的openid
def get_openid(userId):
    user = db.user.find_one({'userId': userId})
    if any(user):
        return user["wxid"]
    return None

#发送模板消息给用户
def sendOrderCountWarningMsgToDoctor(userId,count):
    template_id = "RCDKZMPByqj_0uJXp0JG3iRCxdzwfrm958ftCQdM9pE";
    url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN"
    openid=get_openid(userId)
    if openid is None:
        return
    msg = "明天共有" + str(count) + "人预约了您。"
    token = get_token()
    url = url.replace("ACCESS_TOKEN", token)
    values = {
        "touser": openid,
        "template_id": template_id,
        "url": "",
        "data": {
            "first": {
                "value": msg,
                "color": "#666666"
            },
            "keyword1": {
                "value": "预约申请单",
                "color": "#996666"
            },
            "keyword2": {
                "value": "高",
                "color": "#428bca"
            },

            "remark": {
                "value": "数量:" + str(count),
                "color": "#777777"
            }
        }
    }

    jdata = json.dumps(values)  # 对数据进行JSON格式化编码
    req = urllib2.Request(url, jdata)  # 生成页面请求的完整数据
    response = urllib2.urlopen(req)  # 发送页面请求
    return response.read()

#发送预约提醒给医生，提前一天发送
def warningOrder(userId):
    now = datetime.datetime.now()
    today=datetime.datetime.strptime(str(now.year)+"-"+str(now.month)+"-"+str(now.day)+" 00:00:00","%Y-%m-%d %H:%M:%S")
    begin=today + datetime.timedelta(days=1)
    end = today + datetime.timedelta(days=2)
    #oneDayAgo = str(today)+" 00:00:00" #(now - datetime.timedelta(days=3))
    count = db.order.count({'doctorId':userId,"isPayed":True,"orderDate":{"$gte":str(begin),"$lt":str(end)}})
    if count > 0:
        print "warning order:",userId," count:",count
        sendOrderCountWarningMsgToDoctor(userId,count)

#更新医生的排班状态
def setPaibanStatus(userId):
    now = datetime.datetime.now()
    today = datetime.datetime.strptime(str(now.year) + "-" + str(now.month) + "-" + str(now.day) + " 00:00:00",
                                       "%Y-%m-%d %H:%M:%S")
    yesterday = today - datetime.timedelta(days=1)
    count = db.doctorpb.count({'doctorId': userId,  "orderday": {"$gte": str(yesterday)}})
    if count > 0:
        print "set Paiban True:", userId
        db.user.update({'userId': userId}, {'$set': {'paibaned':True}})
    else:
        print "set Paiban False:", userId
        db.user.update({'userId': userId}, {'$set': {'paibaned': False}})

#计算用户的粉丝数
def compute_fans(userId):
    orders=db.order.count({'doctorId':userId,'isPayed':True})
    fans=db.attention.count({'targetId':userId})
    print "doctorId:",userId," fans:",fans," orders:",orders
    db.user.update({'userId':userId}, {'$set': {'fans':int(fans),"orders":int(orders)}})

#处理医生预约费结算
def one_loop():
    #contents = db.user.find({'typeId':'2','userId':'13851821623'})
    contents = db.user.find({'typeId': '2'})
    for record in contents:
        userId=record["userId"]
        compute_fans(userId)
        check_to_pay_money(userId)
        warningOrder(userId)
        setPaibanStatus(userId)
        time.sleep(0.1)

if __name__ == '__main__':
    print "ldzy jiesuan begined..."
    one_loop()
    print "ldzy jiesuan ended..."
    #pay_person("oeN4jt6ktSRkFVMhziyp_se50Ves",1.123) #for test only







